home *** CD-ROM | disk | FTP | other *** search
- /* ICMP-related user commands */
- #include <stdio.h>
-
- #include "global.h"
- #include "icmp.h"
- #include "ip.h"
- #include "mbuf.h"
- #include "netuser.h"
- #include "internet.h"
- #include "timer.h"
- #include "socket.h"
- #include "proc.h"
- #include "session.h"
- #include "cmdparse.h"
- #include "commands.h"
- #include "tcp.h" /* used for rtt_add() */
-
- static void pingtx __ARGS((int s,void *ping1,void *p));
- static void _setping(void *x);
-
- int Icmp_trace = 0;
- static int Icmp_echo = 1;
-
- static int
- doicmpec(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return setbool(&Icmp_echo,"ICMP echo response accept",argc,argv);
- }
-
- static int
- doicmpstat(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- int i, j;
-
- /* Note that the ICMP variables are shown in column order, because
- * that lines up the In and Out variables on the same line
- */
- for(j = i = 1; i <= NUMICMPMIB; i++) {
- tprintf("(%2u)icmp%-16s%10lu",
- i,Icmp_mib[i].name,Icmp_mib[i].value.integer);
- tputs((j++ % 2) ? " " : "\n");
- }
- if((j % 2) == 0)
- tputs("\n");
-
- return 0;
- }
-
- static int
- doicmptr(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return setbool(&Icmp_trace,"ICMP trace",argc,argv);
- }
-
- int
- doicmp(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- struct cmds Icmpcmds[] = {
- "echo", doicmpec, 0, 0, NULLCHAR,
- "status", doicmpstat, 0, 0, NULLCHAR,
- "trace", doicmptr, 0, 0, NULLCHAR,
- NULLCHAR
- };
-
- return subcmd(Icmpcmds,argc,argv,p);
- }
-
- /* Send ICMP Echo Request packets */
- int
- doping(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- struct proc *pinger = NULLPROC; /* Transmit process */
- struct sockaddr_in from;
- struct icmp icmp;
- struct mbuf *bp;
- int32 timestamp, rtt;
- int s, fromlen;
- struct ping ping;
- struct session *sp;
-
- memset((char *)&ping,0,sizeof(ping));
-
- if((ping.target = resolve(argv[1])) == 0) {
- tprintf(Badhost,argv[1]);
- return 1;
- }
- /* Allocate a session descriptor */
- if((sp = ping.sp = newsession(argv[1],PING,0,0)) == NULLSESSION){
- tputs(Nosess);
- return 1;
- }
- if((sp->s = s = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP)) == -1){
- tputs(Nosocket);
- keywait(NULLCHAR,1);
- freesession(sp);
- return 1;
- }
-
- if(argc > 2)
- ping.len = (int16)min(atoi(argv[2]),1000);
-
- if(argc > 3)
- ping.interval = atol(argv[3]) * 1000L;
-
- #ifdef XXX
- /* This is a hack. If the specified interval is less than one tick,
- * assume it to be in seconds. Otherwise assume milliseconds.
- */
- if(ping.interval < MSPTICK)
- ping.interval *= (1000 / MSPTICK);
- else
- ping.interval /= MSPTICK;
- #endif
-
- /* Optionally ping a range of IP addresses */
- if(argc > 4)
- ping.incflag = 1;
-
- if(ping.interval != 0){
- pinger = newproc("pingtx",1024,pingtx,s,&ping,NULL,0);
- } else {
- /* One shot ping; let echo_proc hook handle response.
- * An ID of MAXINT16 will not be confused with a legal socket
- * number, which is used to identify repeated pings
- */
- pingem(s,ping.target,0,MAXINT16,ping.len);
- freesession(sp);
- return 0;
- }
- /* Now collect the replies */
- for(;;){
- fromlen = sizeof(from);
- if(recv_mbuf(s,&bp,0,(char *)&from,&fromlen) == -1)
- break;
- ntohicmp(&icmp,&bp);
- if(icmp.type != ICMP_ECHO_REPLY || icmp.args.echo.id != s){
- /* Ignore other people's responses */
- free_p(bp);
- continue;
- }
- ping.responses++;
- /* Get stamp */
- if(pullup(&bp,(char *)×tamp,sizeof(timestamp)) != sizeof(timestamp)){
- /* The timestamp is missing! */
- free_p(bp); /* Probably not necessary */
- continue;
- }
- free_p(bp);
-
- /* Compute round trip time, update smoothed estimates */
- rtt = msclock() - timestamp;
- if(ping.incflag){
- tprintf("%s: rtt %lu\n",inet_ntoa(from.sin_addr.s_addr), rtt);
- continue;
- }
- if(ping.responses == 1){
- /* First response, base entire SRTT on it */
- ping.srtt = rtt;
- ping.mdev = 0;
- } else {
- int32 abserr = (rtt > ping.srtt) ? (rtt-ping.srtt) : (ping.srtt-rtt);
- ping.srtt = (7*ping.srtt + rtt + 4) >> 3;
- ping.mdev = (3*ping.mdev + abserr + 2) >> 2;
- }
- }
- if(pinger != NULLPROC)
- killproc(pinger);
- freesession(sp);
- return 0;
- }
-
- void
- echo_proc(int32 source,int32 dest,struct icmp *icmp,struct mbuf *bp)
- {
- int32 timestamp;
-
- if(Icmp_echo && icmp->args.echo.id == MAXINT16
- && pullup(&bp,(char *)×tamp,sizeof(timestamp)) == sizeof(timestamp)) {
- /* Compute round trip time */
- int32 rtt = msclock() - timestamp;
-
- tprintf("%s: rtt %lu\n",inet_ntoa(source),rtt);
- rtt_add(source,(rtt*3)/2);
- }
- free_p(bp);
- }
-
- /* Ping transmit process. Runs until killed */
- static void
- pingtx(int s,void *ping1,void *p)
- {
- struct ping *ping = (struct ping *)ping1;
-
- ping->sent = 0;
-
- if(ping->incflag){
- for(;;){
- tprintf("pinging %s...\n",inet_ntoa(ping->target));
- pingem(s,ping->target++,0,(int16)s,ping->len);
- pause(ping->interval);
- }
- } else {
- tprintf("pinging %s...\n",ping->sp->name);
- for(;;){
- if(ping->sent) {
- tprintf("sent%6lu rcvd%6lu %% %3lu avg rtt%6lu mdev%5lu\n",
- ping->sent,ping->responses,
- (ping->responses*100 + ping->sent/2)/ping->sent,
- ping->srtt,ping->mdev);
- }
- pingem(s,ping->target,(int16)ping->sent++,(int16)s,ping->len);
- pause(ping->interval);
- }
- }
- }
-
-
- /*----------------------------------------------------------------------*
- * Send ICMP Echo Request packet *
- *-----------------------------------------------------------------------*/
- static int
- pingem(
- int s, /* Raw socket on which to send ping */
- int32 target, /* Site to be pinged */
- int16 seq, /* ICMP Echo Request sequence number */
- int16 id, /* ICMP Echo Request ID */
- int16 len) /* Length of optional data field */
- {
- struct mbuf *bp;
- struct icmp icmp;
- struct sockaddr_in to;
-
- int32 clock = msclock();
- int x = (len+sizeof(clock));
- struct mbuf *data = ambufw((int16)(x));
-
- data->cnt = len+sizeof(clock);
-
- /* Set optional data field, if any, to all 55's */
- if(len != 0)
- memset(data->data+sizeof(clock),0x55,len);
-
- /* Insert timestamp and build ICMP header */
- memcpy(data->data,(char *)&clock,sizeof(clock));
- icmpOutEchos++;
- icmpOutMsgs++;
- icmp.type = ICMP_ECHO;
- icmp.code = 0;
- icmp.args.echo.seq = seq;
- icmp.args.echo.id = id;
- if((bp = htonicmp(&icmp,data)) == NULLBUF){
- free_p(data);
- return 0;
- }
- to.sin_family = AF_INET;
- to.sin_addr.s_addr = target;
- send_mbuf(s,bp,0,(char *)&to,sizeof(to));
- return 0;
- }
-
- /*----------------------------------------------------------------------*
- * UNDER CONSTRUCTION !!!! *
- * provide a timer triggered ping to signal our presece to RPSF Servers *
- * Syntax: *
- * setping <address> <interval> *
- *-----------------------------------------------------------------------*/
-
- typedef enum {
- Bad, Suspect, Good
- } Apstate;
-
- static char *apstring[3] = {
- "Bad","Suspect","Good"
- };
-
- typedef struct aping {
- struct aping *next; /* next in list */
- int32 target; /* target to be pinged */
- Apstate state; /* state Bad,Suspect,Good */
- Boolean proc_run; /* True if pocess running */
- struct timer timer; /* connected timer */
- } Aping;
-
- static Aping *Ap; /* start of list */
-
-
- /*----------------------------------------------------------------------*
- *-----------------------------------------------------------------------*/
- int
- dosetping(int argc,char *argv[], void *p)
- {
- int32 target, timeout;
- Aping *ap=0, *app;
-
- if(argc < 2) {
- /*----------------------------------------------------------------*
- * display the Pinglist *
- *-----------------------------------------------------------------*/
- tputs("Status Address Interval\n");
- for (app = Ap; app; app = app->next) {
- tprintf("%-8s %-18s %lu/%lu \n",
- apstring[app->state],
- inet_ntoa(app->target),
- read_timer(&app->timer)/1000,
- dur_timer(&app->timer)/1000);
- }
- return 0;
- }
- /*-------------------------------------------------------------------*
- * give usage information *
- *--------------------------------------------------------------------*/
- if(argc <3) {
- tputs("Usage: setping <address> <interval>\n");
- return 0;
- }
- /*-------------------------------------------------------------------*
- * resolve destination *
- *--------------------------------------------------------------------*/
- if((target = resolve(argv[1])) == 0){
- tprintf(Badhost,argv[1]); /* ain't never heard of*/
- return 1;
- }
- if((timeout = atol(argv[2])) < 60)
- timeout = 60L; /* minimum interval is 60 seconds*/
-
- /*-------------------------------------------------------------------*
- * allocate and fill a list entry *
- *--------------------------------------------------------------------*/
- if (Ap) { /* check if target alreay present*/
- for (app = Ap; app; app = app->next) {
- if (app->target == target) {
- ap = app; /* gotcha! */
- break;
- }
- }
- }
- /*-------------------------------------------------------------------*
- * allocate structure if a new entry to be set *
- *--------------------------------------------------------------------*/
- if (ap == NULL) {
- ap = mxallocw(sizeof(Aping));
- if (Ap == 0)
- Ap = ap;
- else {
- for (app = Ap; app->next; app = app->next) ;
- app->next = ap;
- }
- }
-
- ap->target = target;
- ap->timer.func = (void (*) __ARGS((void *))) _setping; /* what to call on timeout */
- ap->timer.arg = ap; /* dummy value */
- set_timer(&ap->timer,timeout * 1000L); /* set timer duration */
- #ifdef MDEBUG
- sprintf(ap->timer.tname,"%.7s",argv[1]);
- #endif
- /*-------------------------------------------------------------------*
- * just do a one shot ping and restart the timer *
- *--------------------------------------------------------------------*/
- if (ap->proc_run == False)
- _setping(ap);
-
- return 0;
- }
-
-
- /*----------------------------------------------------------------------*
- *-----------------------------------------------------------------------*/
- int
- doresetping(int argc,char *argv[], void *p)
- {
- Aping *app=0, *ap=0;
- int32 target;
-
- if((target = resolve(argv[1])) == 0){
- tprintf(Badhost,argv[1]); /* ain't never heard of*/
- return 1;
- }
-
- /*-------------------------------------------------------------------*
- * isolate the entry *
- * app == entry to be removed *
- * ap == previous entry to be connected *
- *--------------------------------------------------------------------*/
- for (app = Ap; app; app = app->next) {
- if (app->target == target) {
- break;
- }
- ap = app;
- }
-
- if (app == 0) { /* not found */
- tprintf(Badhost,argv[1]);
- return 1;
- }
-
- if (app->timer.state == TIMER_STOP) {
- tprintf("Autoping for %s active, try later...\n",argv[1]);
- return 1;
- }
- /*-------------------------------------------------------------------*
- * disconnect the entry *
- *--------------------------------------------------------------------*/
- if (app == Ap) { /* start of chain */
- Ap = app->next;
- } else {
- ap->next = app->next;
- }
- stop_timer(&app->timer);
- xfree(app); /* terminate the entry */
- return 0;
- }
-
- static void autoping __ARGS((int a,void *p,void *v));
-
-
- /*----------------------------------------------------------------------*
- * this routine is called on each timeout *
- *-----------------------------------------------------------------------*/
- static void
- _setping(void *x)
- {
- Aping *ap = x;
- static char name[20];
-
- sprintf(name,"AP %.15s",inet_ntoa(ap->target));
- /*-------------------------------------------------------------------*
- * spawn an Autoping process *
- *--------------------------------------------------------------------*/
- ap->proc_run = True;
- newproc(name,768,autoping,ap->state,x,NULL,0);
- }
-
- /*----------------------------------------------------------------------*
- * process to be started for each Autoping *
- * sorry, but that goto end thing is needed, cuz I have to reset the *
- * 'proc_run" flag upon exit.. and won't leave that up to the optimizer. *
- * DK5DC *
- *-----------------------------------------------------------------------*/
- static void
- autoping (int oldstate,void *p,void *v)
- {
- Aping *ap = p;
- int s, fromlen;
- struct sockaddr_in from;
- struct mbuf *bp;
- struct icmp icmp;
-
- /*-------------------------------------------------------------------*
- * get a socket
- *--------------------------------------------------------------------*/
- if((s = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP)) == -1){
- tputs(Nosocket);
- goto end;
- }
- stop_timer(&ap->timer); /* stop the timer */
- fromlen = sizeof(from);
- pingem(s,ap->target,0,s,64); /* fire up that ping */
- /*-------------------------------------------------------------------*
- * now wait and collect replies *
- *--------------------------------------------------------------------*/
- alarm(60000L); /* Let each ping timeout after 60 seconds*/
-
- for(;;) {
- if(recv_mbuf(s,&bp,0,(char *)&from,&fromlen) == -1){
- if(errno == EALARM) /* We timed out */
- break;
- alarm(0);
- ap->state = oldstate;
- goto end;
- }
-
- ntohicmp(&icmp,&bp);
- free_p(bp);
-
- if(icmp.type != ICMP_ECHO_REPLY ||
- from.sin_addr.s_addr != ap->target ||
- icmp.args.echo.id != s)
- /* Ignore other people's responses */
- continue;
- alarm(0);
- ap->state = Good; /* Finally change state */
- goto end;
- }
- if (ap->state == Good) {
- ap->state = Suspect;
- } else {
- ap->state = Bad;
- }
-
- end:
- close_s(s);
- start_timer(&ap->timer);
- ap->proc_run = False;
- }
-
-